⚡ 30 秒速记

  • 解析检查语法,引擎再编译与执行
  • 调用栈记录当前函数与返回位置
  • 词法环境决定变量沿哪里查找
  • 普通函数 this 看调用方式,箭头函数捕获外层
  • 闭包保留可达绑定,不等于整段调用永不结束

引擎执行代码时,一边按调用栈管理正在做的事,一边按词法环境查找变量。 代码会先经过解析,具体解释和编译策略由引擎决定;函数调用时进入新的执行上下文,返回时退出。变量的外层关系来自定义位置,普通函数的 this 却要看怎样调用。闭包可以让外层绑定继续可达,所以函数已经返回,相关数据仍可能被后续回调使用。

版本校准: 原理文章中的代码代表特定实现与写作时间。应用到当前项目时,应先确认浏览器、框架或工具的主版本,再区分稳定的规范语义、可变化的内部实现和项目自身约束。

在 V8 引擎中 JavaScript 代码的运行过程主要分成三个阶段

  • 语法分析阶段。 该阶段会对代码进行语法分析,检查是否有语法错误(SyntaxError),如果发现语法错误,会在控制台抛出异常并终止执行
  • 编译阶段。 该阶段会进行执行上下文(Execution Context)的创建,包括创建变量对象、建立作用域链、确定 this 的指向等。每进入一个不同的运行环境时,V8 引擎都会创建一个新的执行上下文。
  • 执行阶段。 将编译阶段中创建的执行上下文压入调用栈,并成为正在运行的执行上下文,代码执行结束后,将其弹出调用栈

其中,语法分析阶段属于编译器通用内容,就不再赘述。前面提到的执行环境、词法环境、作用域、执行上下文等内容都是在编译和执行阶段中产生的概念。

JavaScript 在运行过程中会产生一个调用栈,调用栈遵循 LIFO(先进后出,后进先出)

# 执行上下文的创建

执行上下文的创建离不开 JavaScript 的运行环境,JavaScript 运行环境包括全局环境、函数环境和eval,其中全局环境和函数环境的创建过程如下

  • 第一次载入 JavaScript 代码时,首先会创建一个全局环境。全局环境位于最外层,直到应用程序退出后(例如关闭浏览器和网页)才会被销毁
  • 每个函数都有自己的运行环境,当函数被调用时,则会进入该函数的运行环境。当该环境中的代码被全部执行完毕后,该环境会被销毁。不同的函数运行环境不一样,即使是同一个函数,在被多次调用时也会创建多个不同的函数环境

在不同的运行环境中,变量和函数可访问的其他数据范围不同,环境的行为(比如创建和销毁)也有所区别。而每进入一个不同的运行环境时,JavaScript 都会创建一个新的执行上下文,该过程包括:

  • 建立作用域链(Scope Chain);
  • 创建变量对象(Variable Object,简称 VO);
  • 确定 this 的指向。

由于建立作用域链过程中会涉及变量对象的概念,因此我们先来看看变量对象的创建,再看建立作用域链和确定 this 的指向

# 创建变量对象

什么是变量对象呢?每个执行上下文都会有一个关联的变量对象,该对象上会保存这个上下文中定义的所有变量和函数

webapp
公众号
开发者导航
切换夜间模式
点击侧边栏上一篇
点击侧边栏下一篇
折叠侧边栏
收起全部